/**
 * Dart抽象类：主要用于定义标准，子类可以继承抽象类，也可以实现抽象类接口
 * 1、通过abstract关键字定义
 * 2、抽象方法不能用abstract声明，Dart中没有方法体的方法称为抽象方法
 * 3、子类继承抽象类，必须实现里面的抽象方法
 * 4、把抽象类当做接口实现的话，必须实现里面定义的所有属性和方法
 * 5、抽象类不能被实例化，只有继承他的子类可以
 *
 * extends和implements区别：（和Java类似）
 * 1、如果复用抽象类里面的方法，并且要抽象方法约束子类的话，就用extends继承抽象类
 * 2、如果只把抽象类当做标准的话，就用implements实现抽象类
 */

/**
 * 定义一个Animal，要求它的子类必须包含eat方法
 */
abstract class Animal {
  eat(); // 抽象方法

}

class Dog extends Animal {
  @override
  eat() {
    print("吃骨头");
  }

  run() {
    print("小狗跑");
  }
}

/**
 * Dart中的多态：
 * 允许将子类类型的指针赋值非父类类型的指针，同一个函数调用会有不同的执行效果。
 *
 * 子类的实例赋值给父类的引用
 *
 * 多态就是父类定义一个方法，不去实现，让继承它的子类去实现，每个子类有不同的表现
 */

class Cat extends Animal {
  @override
  eat() {
    print("吃老鼠");
  }

  run() {
    print("小猫跑");
  }
}

/**
 * Dart接口：
 * 没有interface关键字，而是普通类或抽象类都可以作为接口被实现，同样适用implements关键字实现。
 *
 * Dart中，如果实现的类是普通类，会将普通类和抽象中的属性和方法全部复写一遍
 *
 * 因为抽象类可以定义抽象方法，普通类不可以，所以一般如果要实现像Java接口那样的方式，一般会使用抽象类。
 *
 * 建议使用抽象类定义接口。
 */

/**
 * 定义一个DB库，支持MySql、MsSql、Mongodb
 * MySql、MsSql、Mongodb三个类有同样的方法
 */
// 当做接口：接口就是约定，规范
abstract class Db {
  // 数据库连接地址
  String uri;

  add(String data);

  save();

  delete();
}

class MySql implements Db {
  @override
  String uri;

  MySql(this.uri);

  @override
  add(data) {
    print("MySql add -- $data");
  }

  @override
  delete() {
    print("MySql delete");
  }

  @override
  save() {
    print("MySql save");
  }
}

class MsSql implements Db {
  @override
  String uri;

  @override
  add(data) {
    return null;
  }

  @override
  delete() {
    return null;
  }

  @override
  save() {
    return null;
  }
}

class Mongodb implements Db {
  @override
  String uri;

  @override
  add(data) {
    return null;
  }

  @override
  delete() {
    return null;
  }

  @override
  save() {
    return null;
  }
}

main() {
//  Dog d = new Dog();
//  d.eat();
//  d.run();

  // 多态
//  Animal d = new Dog();
//  Animal c = new Cat();
//  d.eat();
//  c.eat();

  MySql mySql = new MySql("xxxxxxxxx");
  mySql.add("111");
  mySql.delete();
  mySql.save();
}
